import { Injectable } from '@nestjs/common';
import { InjectRedis } from '@nestjs-modules/ioredis';
import { Redis } from 'ioredis';

@Injectable()
export class RedisService {
  constructor(@InjectRedis() private readonly ioRedisClient: Redis) {}

  async get(key: string) {
    return await this.ioRedisClient.get(key);
  }

  async set(key: string, value: string | number, ttl?: number) {
    await this.ioRedisClient.set(key, value);

    if (ttl) {
      await this.ioRedisClient.expire(key, ttl);
    }
  }

  async del(key: string) {
    await this.ioRedisClient.del(key);
    return true;
  }

  async hashGet(key: string) {
    return await this.ioRedisClient.hgetall(key);
  }

  async hashSet(key: string, obj: Record<string, any>, ttl?: number) {
    for (const name in obj) {
      await this.ioRedisClient.hset(key, name, obj[name]);
    }

    if (ttl) {
      await this.ioRedisClient.expire(key, ttl);
    }
  }

  //封装实现排行榜功能方法

  async zRankingList(key: string, start: number = 0, end: number = -1) {
    const keys = await this.ioRedisClient.zrange(key, start, end, 'WITHSCORES');
    const rankingList = {};
    for(let i = 0; i< keys.length; i+=2){
      rankingList[keys[i]] = keys[i+1];
    }
    return rankingList;
  }

  async zAdd(key: string, members: Record<string, number>) {
    const mems = [];
    for(let memberKey in members) {
      mems.push(members[memberKey], memberKey);
    }
    return this.ioRedisClient.zadd(key, ...mems);
  }

  async zScore(key: string, member: string) {
    return this.ioRedisClient.zscore(key, member);
  }

  async zRank(key: string, member: string) {
    return this.ioRedisClient.zrank(key, member);
  }

  async zIncr(key: string, member: string, increment: number) {
    return this.ioRedisClient.zincrby(key, increment, member);
  }

  async zUnion(newKey: string, keys: string[]) {
    if(!keys.length) {
      return []
    };
    if(keys.length === 1) {
      return this.zRankingList(keys[0]);
    }

    await this.ioRedisClient.zunionstore(newKey, keys.length, ...keys);

    return this.zRankingList(newKey);
  }

  async keys(pattern: string) {
    return this.ioRedisClient.keys(pattern);
  }

  // 抽离出scan的方法
  async scan(pattern: string, count = 100): Promise<string[]> {
    let cursor = '0';
    let keys: string[] = [];

    do {
      const reply = await this.ioRedisClient.scan(cursor, 'MATCH', pattern, 'COUNT', count);
      cursor = reply[0];
      keys = keys.concat(reply[1]);
    } while (cursor !== '0');

    return keys;
  }
}